home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
Aminet 7
/
Aminet 7 - August 1995.iso
/
Aminet
/
comm
/
net
/
rhslip38_9_030.lha
/
rhslip
/
src
/
device_funcs.c
< prev
next >
Wrap
C/C++ Source or Header
|
1994-01-26
|
52KB
|
2,039 lines
/* $Id: device_funcs.c,v 38.9 1994/01/25 09:04:06 ppessi Exp $
** $Source: /m/lerppu/u3/projects/Dec93/ohtatcp/amitcp/src/devs/rhslip/RCS/device_funcs.c,v $
** $State: Exp $
** $Revision: 38.9 $
** $Date: 1994/01/25 09:04:06 $
** $Author: ppessi $
**
** Amiga SANA-II Example SLIP device driver.
**
** (C) Copyright 1992 Commodore-Amiga, Inc.
**
*/
#ifndef USEPRIORITY /* add write requests in priority order */
# define USEPRIORITY 1
#endif
#ifndef DEMANDREAD
# define DEMANDREAD 1
#endif
#include "slip_device.h"
#define DEBUG 0
#if DEBUG
#include "syslog.h"
#else
#define debug(x)
#endif
#include <dos/dostags.h>
#include <dos/rdargs.h>
#include <intuition/intuition.h>
#include <clib/exec_protos.h>
#include <clib/dos_protos.h>
#include <clib/utility_protos.h>
#include <clib/timer_protos.h>
#include <clib/alib_stdio_protos.h>
#include <clib/intuition_protos.h>
#include <pragmas/exec_pragmas.h>
#include <pragmas/dos_pragmas.h>
#include <pragmas/utility_pragmas.h>
#include <pragmas/timer_pragmas.h>
#include <pragmas/intuition_pragmas.h>
#include <string.h>
#include "device_protos.h"
/* Correct prototype for the CheckIO.
* (The one in clib/exec_protos.h has wrong return value type: BOOL (16 bits)
* instead of a pointer (32 bits)!)
*/
struct IORequest * CheckIO(struct IORequest *req);
/*
** External variables and functions
**
*/
extern struct SLIPDevice *ExtDeviceBase;
extern ULONG IPToNum(STRPTR ipstr);
extern VOID kprintf(STRPTR fmt, ...);
const char SLIPName[] = SLIPDEVNAME;
/*
** Device Open vector
**
** a1 - SANA2 IO Request
** a6 - Pointer to our device base
** d0 - Unit number
** d1 - Flags
**
*/
ULONG ASM DevOpen(REG(a1) struct IOSana2Req *ios2,
REG(a6) struct SLIPDevice *SLIPDevice,
REG(d0) ULONG s2unit,
REG(d1) ULONG s2flags)
{
struct SLIPDevUnit *sdu;
struct TagItem *bufftag;
struct Library *UtilityBase;
struct BufferManagement *bm;
ULONG returncode;
BOOL status = FALSE;
/* Make sure our open remains single-threaded. */
ObtainSemaphore(&SLIPDevice->sd_Lock); /* Enforce single threading since we may need to
Wait() when starting up the Unit process */
#if DEBUG
initsyslog();
#endif
SLIPDevice->sd_Device.lib_OpenCnt++; /* So we won't expunge ourselves... */
if(s2unit < SD_MAXUNITS) /* Legal Unit? */
{
if(sdu = InitSLIPUnit(s2unit)) /* Initialize the Unit */
{
if(UtilityBase = OpenLibrary("utility.library",37L)) /* For Tag functions */
{
/* Allocate a structure to store the pointers to the callback routines. */
if(bm = AllocMem(sizeof(struct BufferManagement),MEMF_CLEAR|MEMF_PUBLIC))
{
/* Note: I don't complain if I can't find pointers to the callback routines.
This is because there are some programs that may need to open me, but
will never use any device commands that require the callbacks. */
if(bufftag = FindTagItem(S2_CopyToBuff, (struct TagItem *)ios2->ios2_BufferManagement))
{
bm->bm_CopyToBuffer = (SANA2_CTB) bufftag->ti_Data;
}
if(bufftag = FindTagItem(S2_CopyFromBuff, (struct TagItem *)ios2->ios2_BufferManagement))
{
bm->bm_CopyFromBuffer = (SANA2_CFB) bufftag->ti_Data;
}
AddTail((struct List *)&sdu->sdu_BuffMgmt,(struct Node *)bm);
/* Everything went okay. */
status = TRUE;
returncode = 0;
SLIPDevice->sd_Device.lib_OpenCnt++;
SLIPDevice->sd_Device.lib_Flags &=~LIBF_DELEXP;
sdu->sdu_Unit.unit_OpenCnt++;
/* Fix up the initial io request */
ios2->ios2_BufferManagement = (VOID *)bm;
ios2->ios2_Req.io_Error = 0;
ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_REPLYMSG;
ios2->ios2_Req.io_Unit = sdu;
ios2->ios2_Req.io_Device = SLIPDevice;
}
CloseLibrary(UtilityBase);
}
}
}
/* See if something went wrong. */
if(!status)
{
ios2->ios2_Req.io_Error = IOERR_OPENFAIL;
ios2->ios2_Req.io_Unit = (struct Unit *) -1;
ios2->ios2_Req.io_Device = (struct Device *) -1;
returncode = IOERR_OPENFAIL;
}
SLIPDevice->sd_Device.lib_OpenCnt--;
ReleaseSemaphore(&SLIPDevice->sd_Lock);
return(returncode);
}
/*
** Device Close vector.
**
** a1 - IOReq
** a6 - Device Pointer
**
*/
BPTR ASM DevClose(REG(a1) struct IOSana2Req *ios2,
REG(a6) struct SLIPDevice *SLIPDevice)
{
struct SLIPDevUnit *sdu;
BPTR seglist = 0L;
ObtainSemaphore(&SLIPDevice->sd_Lock);
sdu = (struct SLIPDevUnit *)ios2->ios2_Req.io_Unit;
/* Trash the io_Device and io_Unit fields so that any attempt to use this
request will die immediatly. */
ios2->ios2_Req.io_Device = (struct Device *) -1;
ios2->ios2_Req.io_Unit = (struct Unit *) -1;
/* I always shut the unit process down if the open count drops to zero.
That way, if I need to expunge, I never have to Wait(). */
sdu->sdu_Unit.unit_OpenCnt--;
if(!sdu->sdu_Unit.unit_OpenCnt)
{
ExpungeUnit(sdu);
}
SLIPDevice->sd_Device.lib_OpenCnt--;
ReleaseSemaphore(&SLIPDevice->sd_Lock);
/* Check to see if we've been asked to expunge. */
if(SLIPDevice->sd_Device.lib_Flags & LIBF_DELEXP)
seglist = DevExpunge(SLIPDevice);
return(seglist);
}
/*
** Device Expunge vector
**
** a6 - Device base
**
** Note: You may NEVER EVER Wait() in expunge. Period.
** Don't even *think* about it.
*/
BPTR ASM DevExpunge(REG(a6) struct SLIPDevice *SLIPDevice)
{
BPTR seglist;
ULONG devbase;
LONG devbasesize;
if(SLIPDevice->sd_Device.lib_OpenCnt)
{
/* Sorry, we're busy. We'll expunge later on
if we can. */
SLIPDevice->sd_Device.lib_Flags |= LIBF_DELEXP;
seglist = (BPTR)0L;
}
else
{
/* Free up our library base and function table after
removing ourselves from the library list. */
Remove((struct Node *)SLIPDevice);
seglist = SLIPDevice->sd_SegList;
devbase = (ULONG) SLIPDevice;
devbasesize = (ULONG)SLIPDevice->sd_Device.lib_NegSize;
devbase = devbase - devbasesize;
devbasesize += (ULONG)SLIPDevice->sd_Device.lib_PosSize;
#if DEBUG
uninitsyslog();
#endif
FreeMem((APTR)devbase,devbasesize);
ExtDeviceBase = NULL;
}
return(seglist);
}
/*
** InitSLIPUnit
**
** Initialize (if needed) a new SLIP device Unit and process.
**
*/
struct SLIPDevUnit *InitSLIPUnit(ULONG s2unit)
{
struct SLIPDevice *SLIPDevice = SLIPBase;
struct SLIPDevUnit *sdu;
struct TagItem NPTags[]={NP_Entry, 0, NP_Name, 0, NP_Priority, SLIP_PRI, TAG_DONE, 0};
struct MsgPort *replyport;
/* Check to see if the Unit is already up and running. If
it is, just drop through. If not, try to start it up. */
if(!SLIPDevice->sd_Units[s2unit])
{
/* Open up dos.library */
if(SLIPDevice->sd_DOSBase = OpenLibrary("dos.library",37L))
{
/* Allocate a new Unit structure */
if(sdu = AllocMem(sizeof(struct SLIPDevUnit), MEMF_CLEAR|MEMF_PUBLIC))
{
/* Do some initialization on the Unit structure */
NewList(&sdu->sdu_Unit.unit_MsgPort.mp_MsgList);
sdu->sdu_Unit.unit_MsgPort.mp_Node.ln_Type = NT_MSGPORT;
sdu->sdu_Unit.unit_MsgPort.mp_Flags = PA_IGNORE;
sdu->sdu_Unit.unit_MsgPort.mp_Node.ln_Name = (char *)SLIPName;
sdu->sdu_UnitNum = s2unit;
sdu->sdu_Device = (struct Device *) SLIPDevice;
/* Try to read in our configuration file */
if(ReadConfig(sdu))
{
/* Start up the unit process */
if(replyport = CreateMsgPort())
{
SLIPDevice->sd_Startup.Msg.mn_ReplyPort = replyport;
SLIPDevice->sd_Startup.Device = (struct Device *) SLIPDevice;
SLIPDevice->sd_Startup.Unit = (struct Unit *)sdu;
NPTags[0].ti_Data = (ULONG) &DevProcCEntry;
NPTags[1].ti_Data = (ULONG) SLIPName; /* Process name */
/* Rhialto: use opener's priority */
NPTags[2].ti_Data = (ULONG) FindTask(NULL)->tc_Node.ln_Pri;
/*ExtDeviceBase = (struct Library *)SLIPDevice;*/
if(sdu->sdu_Proc = CreateNewProc(NPTags))
{
PutMsg(&sdu->sdu_Proc->pr_MsgPort,(struct Message *)&SLIPDevice->sd_Startup);
WaitPort(replyport);
GetMsg(replyport);
}
DeleteMsgPort(replyport);
}
}
if(!sdu->sdu_Proc)
{
/* The Unit process couldn't start for some reason, so free the Unit structure. */
FreeMem(sdu,sizeof(struct SLIPDevUnit));
}
else
{
/* Set up the Unit structure pointer in the device base */
SLIPDevice->sd_Units[s2unit] = (struct Unit *)sdu;
}
}
CloseLibrary(SLIPDevice->sd_DOSBase);
}
}
return((struct SLIPDevUnit *)SLIPDevice->sd_Units[s2unit]);
}
/*
**
** ExpungeUnit
**
** Tells a unit process to go away...
**
** This function is called from the DevClose routine when the open count for a
** unit reaches zero. This routine signals the unit process to exit and then
** waits for the unit process to acknowledge. The unit structure is then
** freed.
*/
VOID ExpungeUnit(struct SLIPDevUnit *sdu)
{
struct SLIPDevice *SLIPDevice = SLIPBase;
struct Task *unittask;
unittask = (struct Task *)sdu->sdu_Proc;
sdu->sdu_Proc = (struct Process *)FindTask(0L);
Signal(unittask,SIGBREAKF_CTRL_F);
Wait(SIGBREAKF_CTRL_F);
SLIPDevice->sd_Units[sdu->sdu_UnitNum] = NULL;
FreeMem(sdu, sizeof(struct SLIPDevUnit));
}
/*
**
** ReadConfig
**
** Attempt to read in and parse the driver's configuration file.
**
** The files are named by ENV:SANA2/(c)slipX.config where X is the decimal
** representation of the device's unit number.
**
*/
BOOL ReadConfig(struct SLIPDevUnit *sdu)
{
UBYTE *linebuff,buff[40];
STRPTR termchar;
struct RDArgs *rdargs;
BPTR ConfigFile;
BOOL status = FALSE;
ULONG linenum=0;
/* Create the name of our config file.. */
sprintf(buff,"ENV:SANA2/rhslip%ld.config",(ULONG)sdu->sdu_UnitNum);
if(ConfigFile = Open(buff,MODE_OLDFILE))
goto config_open;
#if CSLIP
sprintf(buff,"ENV:SANA2/cslip%ld.config",(ULONG)sdu->sdu_UnitNum);
if(ConfigFile = Open(buff,MODE_OLDFILE))
goto config_open;
#endif
sprintf(buff,"ENV:SANA2/slip%ld.config",(ULONG)sdu->sdu_UnitNum);
/* ...and open it. */
if(ConfigFile = Open(buff,MODE_OLDFILE))
{
config_open:
/* Here, I use ReadArgs() to do the file parsing for me. */
if(linebuff = AllocMem(256,MEMF_CLEAR|MEMF_PUBLIC))
{
if(rdargs = AllocDosObject(DOS_RDARGS, NULL))
{
while(FGets(ConfigFile, linebuff, 255))
{
/* ppessi: This is more robust than LONG array */
struct {
STRPTR a_SerDevName;
ULONG *a_SerUnitNum;
ULONG *a_BaudRate;
STRPTR a_IPAddr;
ULONG *a_MTU;
ULONG a_CarrierDetect;
ULONG a_7Wire;
ULONG a_EofMode;
} args[1];
const UBYTE template[] =
"SERNAME/A,"
"SERUNIT/A/N,"
"SERBAUD/A/N,"
"IPSTR/A,"
"MTU/K/N,"
"CD=CARRIERDETECT/S,7WIRE/S,EOF=EOFMODE/S";
linenum++;
if(linebuff[0] == '#') /* Skip comment lines */
continue;
rdargs->RDA_Source.CS_Buffer = linebuff;
rdargs->RDA_Source.CS_Length = 256;
rdargs->RDA_Source.CS_CurChr = 0;
/* ReadArgs() requires that the line be null-terminated
or funny things happen. */
termchar = (STRPTR) linebuff + strlen(linebuff);
*termchar = '\n';
termchar++;
*termchar = 0;
memset(args, 0, sizeof(*args));
/* Parse the line...*/
/* ppessi: New parameters */
if (ReadArgs(template, (LONG *)args, rdargs))
{
strncpy(sdu->sdu_SerDevName, args->a_SerDevName, sizeof(sdu->sdu_SerDevName));
sdu->sdu_SerUnitNum = *args->a_SerUnitNum;
sdu->sdu_BaudRate = *args->a_BaudRate;
sdu->sdu_StAddr = /* Rhialto */
sdu->sdu_HwAddr = IPToNum(args->a_IPAddr);
if (args->a_CarrierDetect)
sdu->sdu_State |= SLIPUF_CD;
debug(("Config: CD %d\n", sdu->sdu_State & SLIPUF_CD));
if (args->a_7Wire)
sdu->sdu_State |= SLIPUF_7WIRE;
debug(("Config: 7W %d\n", sdu->sdu_State & SLIPUF_7WIRE));
if (args->a_EofMode)
sdu->sdu_State |= SLIPUF_EOFMODE;
debug(("Config: EOFMODE %d\n", sdu->sdu_State & SLIPUF_EOFMODE));
/* ppessi: some SLIP drivers are broken, break this too... */
if (args->a_MTU && *args->a_MTU < SLIP_SERIAL_BUFSIZE / 2 - BUF_SLOP)
{
sdu->sdu_MTU = *args->a_MTU;
}
else
{
/* 1006 byte max */
sdu->sdu_MTU = SLIP_MTU;
}
debug(("Config: MTU=%d\n", sdu->sdu_MTU));
status = TRUE;
FreeArgs(rdargs);
break;
} else {
struct Library *IntuitionBase;
struct EasyStruct es;
if(IntuitionBase = OpenLibrary("intuition.library",37L))
{
es.es_StructSize=sizeof(struct EasyStruct);
es.es_Flags=0;
es.es_Title=(char *)SLIPName;
es.es_TextFormat="Error in configuration file on line %ld.";
es.es_GadgetFormat="Okay";
EasyRequestArgs(NULL, &es, 0, &linenum);
CloseLibrary(IntuitionBase);
}
break;
}
}
FreeDosObject(DOS_RDARGS,rdargs);
}
FreeMem(linebuff, 256);
}
Close(ConfigFile);
}
return(status);
}
/*
**
** BeginIO
**
** This is the dispatch point for the driver's incoming IORequests.
**
*/
#define SLIP_IMMEDIATES 0L
VOID ASM DevBeginIO(REG(a1) struct IOSana2Req *ios2,
REG(a6) struct SLIPDevice *SLIPDevice)
{
ios2->ios2_Req.io_Message.mn_Node.ln_Type = NT_MESSAGE;
if(ios2->ios2_Req.io_Command < S2_END)
{
if((1L << ios2->ios2_Req.io_Command) & SLIP_IMMEDIATES)
{
PerformIO(ios2);
}
else
{
ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
PutMsg((struct MsgPort *)ios2->ios2_Req.io_Unit,(struct Message *)ios2);
}
}
else
{
ios2->ios2_Req.io_Error = IOERR_NOCMD;
TermIO(ios2);
}
}
/*
** This routine is used to dispatch an IO request either from BeginIO
** or from the Unit process.
*/
VOID PerformIO(struct IOSana2Req *ios2)
{
struct SLIPDevUnit *sdu;
sdu = (struct SLIPDevUnit *)ios2->ios2_Req.io_Unit;
ios2->ios2_Req.io_Error = 0;
switch(ios2->ios2_Req.io_Command)
{
case CMD_READ: ReadPacket(sdu,ios2);
break;
case CMD_WRITE: WritePacket(sdu,ios2);
break;
case S2_DEVICEQUERY: DeviceQuery(sdu,ios2);
break;
case S2_GETSTATIONADDRESS: GetStationAddress(sdu,ios2);
break;
case S2_CONFIGINTERFACE: ConfigInterface(sdu,ios2);
break;
case S2_ADDMULTICASTADDRESS:
case S2_DELMULTICASTADDRESS:
case S2_MULTICAST: ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
TermIO(ios2);
break;
case S2_BROADCAST: WritePacket(sdu,ios2);
break;
case S2_TRACKTYPE: TrackType(sdu,ios2);
break;
case S2_UNTRACKTYPE: UnTrackType(sdu,ios2);
break;
case S2_GETTYPESTATS: GetTypeStats(sdu,ios2);
break;
case S2_GETSPECIALSTATS: GetSpecialStats(sdu,ios2);
break;
case S2_GETGLOBALSTATS: GetGlobalStats(sdu,ios2);
break;
case S2_ONEVENT: OnEvent(sdu,ios2);
break;
case S2_READORPHAN: ReadOrphan(sdu,ios2);
break;
case S2_ONLINE: Online(sdu,ios2);
break;
case S2_OFFLINE: Offline(sdu,ios2);
break;
default: ios2->ios2_Req.io_Error = IOERR_NOCMD;
TermIO(ios2);
break;
}
}
/*
** This function returns any device specific statistics that
** we may have. Unfortunately, we don't have any SLIP specific
** statistics.
*/
VOID GetSpecialStats(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
struct Sana2SpecialStatHeader *stats;
stats = (struct Sana2SpecialStatHeader *)ios2->ios2_StatData;
#if CSLIP
{
int count;
struct Sana2SpecialStatRecord *r;
count = stats->RecordCountMax;
if (count > 11)
count = 11;
r = (struct Sana2SpecialStatRecord *)(stats + 1);
r = &r[count - 1];
switch (count) {
case 11:
r->Type = S2SS_CSLIP_I_TOSSED;
r->String = "i_tossed";
r->Count = sdu->sdu_slcompress.sls_i_tossed;
r--;
case 10:
r->Type = S2SS_CSLIP_I_ERROR;
r->String = "i_error";
r->Count = sdu->sdu_slcompress.sls_i_error;
r--;
case 9:
r->Type = S2SS_CSLIP_I_COMPRESSED;
r->String = "i_compressed";
r->Count = sdu->sdu_slcompress.sls_i_compressed;
r--;
case 8:
r->Type = S2SS_CSLIP_I_UNCOMPRESSED;
r->String = "i_uncompressed";
r->Count = sdu->sdu_slcompress.sls_i_uncompressed;
r--;
case 7:
r->Type = S2SS_CSLIP_I_IP;
r->String = "i_ip";
r->Count = sdu->sdu_slcompress.sls_i_ip;
r--;
case 6:
r->Type = S2SS_CSLIP_O_MISSES;
r->String = "o_misses";
r->Count = sdu->sdu_slcompress.sls_o_misses;
r--;
case 5:
r->Type = S2SS_CSLIP_O_SEARCHES;
r->String = "o_searches";
r->Count = sdu->sdu_slcompress.sls_o_searches;
r--;
case 4:
r->Type = S2SS_CSLIP_O_COMPRESSED;
r->String = "o_compressed";
r->Count = sdu->sdu_slcompress.sls_o_compressed;
r--;
case 3:
r->Type = S2SS_CSLIP_O_UNCOMPRESSED;
r->String = "o_uncompressed";
r->Count = sdu->sdu_slcompress.sls_o_uncompressed;
r--;
case 2:
r->Type = S2SS_CSLIP_O_TCP;
r->String = "o_tcp";
r->Count = sdu->sdu_slcompress.sls_o_tcp;
r--;
case 1:
r->Type = S2SS_CSLIP_O_NONTCP;
r->String = "o_nontcp";
r->Count = sdu->sdu_slcompress.sls_o_nontcp;
case 0:
break;
}
stats->RecordCountSupplied = count;
}
#else
stats->RecordCountSupplied = 0;
#endif
TermIO(ios2);
}
/*
** This function returns the global statistics for the
** slip device.
*/
VOID GetGlobalStats(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
struct Sana2DeviceStats *stats;
stats = (struct Sana2DeviceStats *)ios2->ios2_StatData;
stats->PacketsReceived = sdu->sdu_Stats.PacketsReceived;
stats->PacketsSent = sdu->sdu_Stats.PacketsSent;
stats->BadData = sdu->sdu_Stats.BadData;
stats->Overruns = sdu->sdu_Stats.Overruns;
stats->UnknownTypesReceived = sdu->sdu_Stats.UnknownTypesReceived;
stats->Reconfigurations = sdu->sdu_Stats.Reconfigurations;
stats->LastStart.tv_secs = sdu->sdu_Stats.LastStart.tv_secs;
stats->LastStart.tv_micro = sdu->sdu_Stats.LastStart.tv_micro; /* Rhialto */
/* Rhialto: huh?
ios2->ios2_Req.io_Error = S2ERR_NOT_SUPPORTED;
ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
*/
TermIO(ios2);
}
/*
** This function returns statistics for a specific
** type of packet that is being tracked. Unfortunately,
** SLIP can't differentiate between different packet
** types, which makes packet type tracking essentially
** useless as the numbers would essentially be the same
** as those found via S2_GETGLOBALSTATS.
**
** Just to be thourough, I have arbitrarily picked
** the packet type for SLIP IP packets to be 2048, the
** same as tha used for Ethernet. This will at least
** allow you to track IP packets.
*/
VOID GetTypeStats(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
struct Sana2PacketTypeStats *stats;
struct SuperS2PTStats *sstats;
ObtainSemaphore(&sdu->sdu_ListLock);
stats = (struct Sana2PacketTypeStats *)ios2->ios2_StatData;
sstats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
while(sstats->ss_Node.mln_Succ)
{
if(ios2->ios2_PacketType == sstats->ss_PType)
{
stats->PacketsSent = sstats->ss_Stats.PacketsSent;
stats->PacketsReceived = sstats->ss_Stats.PacketsReceived;
stats->BytesSent = sstats->ss_Stats.BytesSent;
stats->BytesReceived = sstats->ss_Stats.BytesReceived;
stats->PacketsDropped = sstats->ss_Stats.PacketsDropped;
break;
}
sstats = (struct SuperS2PTStats *)sstats->ss_Node.mln_Succ;
}
ReleaseSemaphore(&sdu->sdu_ListLock);
if(!sstats->ss_Node.mln_Succ)
{
ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
ios2->ios2_WireError = S2WERR_NOT_TRACKED;
}
TermIO(ios2);
}
/*
** This function adds a packet type to the list
** of those that are being tracked.
*/
VOID TrackType(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
struct SuperS2PTStats *stats;
ObtainSemaphore(&sdu->sdu_ListLock);
stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
while(stats->ss_Node.mln_Succ)
{
if(ios2->ios2_PacketType == stats->ss_PType)
{
ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
ios2->ios2_WireError = S2WERR_ALREADY_TRACKED;
break; /* Rhialto */
}
stats = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
}
if(!stats->ss_Node.mln_Succ)
{
if(stats = AllocMem(sizeof(struct SuperS2PTStats),MEMF_CLEAR|MEMF_PUBLIC))
{
stats->ss_PType = ios2->ios2_PacketType; /* Rhialto */
if(ios2->ios2_PacketType == 2048)
sdu->sdu_IPTrack = stats;
AddTail((struct List *)&sdu->sdu_Track,(struct Node *)stats);
}
}
ReleaseSemaphore(&sdu->sdu_ListLock);
TermIO(ios2);
}
/*
** This function removes a packet type from the
** list of those that are being tracked.
*/
VOID UnTrackType(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
struct SuperS2PTStats *stats;
struct SuperS2PTStats *stats_next;
ObtainSemaphore(&sdu->sdu_ListLock);
stats = (struct SuperS2PTStats *)sdu->sdu_Track.mlh_Head;
while(stats->ss_Node.mln_Succ)
{
stats_next = (struct SuperS2PTStats *)stats->ss_Node.mln_Succ;
if(ios2->ios2_PacketType == stats->ss_PType)
{
if(ios2->ios2_PacketType == 2048)
sdu->sdu_IPTrack = NULL;
Remove((struct Node *)stats);
FreeMem(stats,sizeof(struct SuperS2PTStats));
stats = NULL;
break;
}
stats = stats_next;
}
if(stats)
{
ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
ios2->ios2_WireError = S2WERR_NOT_TRACKED;
}
ReleaseSemaphore(&sdu->sdu_ListLock);
TermIO(ios2);
}
/*
** This function is called whenever we receive a packet
** from the serial device driver.
**
*/
VOID PacketReceived(struct SLIPDevUnit *sdu, ULONG length)
{
sdu->sdu_Stats.PacketsReceived++;
if(sdu->sdu_IPTrack)
{
sdu->sdu_IPTrack->ss_Stats.PacketsReceived++;
sdu->sdu_IPTrack->ss_Stats.BytesReceived+=length;
}
}
/*
** This function is called whenever a packet is
** sent to the serial device driver.
*/
VOID PacketSent(struct SLIPDevUnit *sdu, ULONG length)
{
sdu->sdu_Stats.PacketsSent++;
if(sdu->sdu_IPTrack)
{
sdu->sdu_IPTrack->ss_Stats.PacketsSent++;
sdu->sdu_IPTrack->ss_Stats.BytesSent+=length;
}
}
/*
** This function is called whenever a packet that
** is too large is received.
*/
VOID PacketOverrun(struct SLIPDevUnit *sdu)
{
#if CSLIP
sl_uncompress_tcp(NULL, TYPE_ERROR, &sdu->sdu_slcompress);
#endif
sdu->sdu_Stats.Overruns++;
DoEvent(sdu, S2EVENT_RX);
}
/*
** This function is called whenever a packet with
** garbage data is encountered.
*/
VOID ReceivedGarbage(struct SLIPDevUnit *sdu)
{
#if CSLIP
sl_uncompress_tcp(NULL, TYPE_ERROR, &sdu->sdu_slcompress);
#endif
sdu->sdu_Stats.BadData++;
DoEvent(sdu, S2EVENT_RX);
}
/*
** This function is called whenever a packet
** is dropped by the SLIP driver.
*/
VOID PacketDropped(struct SLIPDevUnit *sdu)
{
if(sdu->sdu_IPTrack)
{
sdu->sdu_IPTrack->ss_Stats.PacketsDropped++;
}
}
/*
** This function is used to return an IO request
** back to the sender.
*/
VOID TermIO(struct IOSana2Req *ios2)
{
if(!(ios2->ios2_Req.io_Flags & IOF_QUICK))
ReplyMsg((struct Message *)ios2);
}
/*
** The device AbortIO() entry point.
**
** A1 - The IO request to be aborted.
** A3 - The unit pointer NOT!
** A6 - The device base.
*/
ULONG ASM DevAbortIO(REG(a1) struct IOSana2Req *ios2,
REG(a6) struct SLIPDevice *SLIPDevice)
{
struct SLIPDevUnit *sdu = (struct SLIPDevUnit *)ios2->ios2_Req.io_Unit;
ULONG result = 0L;
ObtainSemaphore(&sdu->sdu_ListLock);
if(ios2->ios2_Req.io_Message.mn_Node.ln_Type != NT_REPLYMSG)
{
switch(ios2->ios2_Req.io_Command)
{
case CMD_READ: result=AbortReq(&sdu->sdu_Rx,ios2);
break;
case CMD_WRITE: result=AbortReq(&sdu->sdu_Tx,ios2);
break;
case S2_READORPHAN: result=AbortReq(&sdu->sdu_RxOrph,ios2);
break;
case S2_ONEVENT: result=AbortReq(&sdu->sdu_Events,ios2);
break;
default: result=IOERR_NOCMD;
break;
}
}
ReleaseSemaphore(&sdu->sdu_ListLock);
return(result);
}
/*
** This funcion is used to locate an IO request in a linked
** list and abort it if found.
*/
ULONG AbortReq(struct MinList *minlist, struct IOSana2Req *ios2)
{
struct Node *node, *next;
ULONG result=IOERR_NOCMD;
node = (struct Node *)minlist->mlh_Head;
while(node->ln_Succ)
{
next = node->ln_Succ;
if(node == (struct Node *)ios2)
{
Remove((struct Node *)ios2);
ios2->ios2_Req.io_Error = IOERR_ABORTED;
TermIO(ios2);
result = 0;
}
node = next;
}
return(result);
}
/*
** This function handles S2_CONFIGINTERFACE commands.
*/
VOID ConfigInterface(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
/* Note: we may only be configured once. */
if(!(sdu->sdu_State & SLIPUF_CONFIG))
{
if(OpenSerial(sdu))
{
CopyMem(&sdu->sdu_StAddr,&ios2->ios2_SrcAddr,4);
sdu->sdu_State |= SLIPUF_CONFIG;
}
}
else
{
/* Sorry, we're already configured. */
ios2->ios2_Req.io_Error = S2ERR_BAD_STATE;
ios2->ios2_WireError = S2WERR_IS_CONFIGURED;
}
TermIO(ios2);
}
/*
** This function handles S2_GETSTATIONADDRESS commands.
**
** We don't really have a hardware address, so we will
** just clear the source address field.
** Rhialto: What we want is the config file address as hardware
*8 address, and the S2_CONFIGINTERFACE address as current address.
*/
VOID GetStationAddress(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
memset(ios2->ios2_DstAddr, 0, SANA2_MAX_ADDR_BYTES);
memset(ios2->ios2_SrcAddr, 0, SANA2_MAX_ADDR_BYTES);
memcpy(ios2->ios2_SrcAddr, &sdu->sdu_StAddr, 4);
memcpy(ios2->ios2_DstAddr, &sdu->sdu_HwAddr, 4);
TermIO(ios2);
}
/*
** This function handles S2_DEVICEQUERY comands.
** Rhialto: Give the format of the data, and the *correct* size!
*/
VOID DeviceQuery(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
struct Sana2DeviceQuery *sdq;
sdq = (struct Sana2DeviceQuery *)ios2->ios2_StatData;
sdq->DevQueryFormat = 0;
sdq->DeviceLevel = 0;
sdq->AddrFieldSize = 32; /* 32-bit IP address */
sdq->MTU = sdu->sdu_MTU; /* ppessi: configureable MTU */
sdq->BPS = sdu->sdu_BaudRate;
#if CSLIP
sdq->HardwareType = S2WireType_CSLIP;
#else
sdq->HardwareType = S2WireType_SLIP;
#endif
sdq->SizeSupplied = sizeof(*sdq);
TermIO(ios2);
}
/*
** This function is used for handling CMD_WRITE
** commands.
*/
VOID WritePacket(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
/* Make sure that we are online. */
if(sdu->sdu_State & SLIPUF_ONLINE)
{
/* Make sure it's a legal length. */
if(ios2->ios2_DataLength <= sdu->sdu_MTU)
{
/* See if our serial CMD_WRITE command is busy. If it's not, send
the IO request to SendPacket. */
if(CheckIO((struct IORequest *)sdu->sdu_SerTx))
{
WaitIO((struct IORequest *)sdu->sdu_SerTx);
/* See if modem have dropped carrier */
if (sdu->sdu_State & SLIPUF_CD)
{
sdu->sdu_SerTx->IOSer.io_Command = SDCMD_QUERY;
if(DoIO((struct IORequest *)sdu->sdu_SerTx) ||
(sdu->sdu_SerTx->io_Status & (1 << 5)))
{
/* We're online, so shut everything down. */
CloseSerial(sdu);
DoOffline(sdu);
DoEvent(sdu, S2EVENT_OFFLINE);
debug(("Carrier Dropped\n"));
/* Sorry, we're offline */
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
TermIO(ios2);
return;
}
}
SendPacket(sdu, ios2);
}
else
{
/* We'll have to queue the packet for later...*/
ios2->ios2_Req.io_Flags &= ~IOF_QUICK;
ObtainSemaphore(&sdu->sdu_ListLock);
#if USEPRIORITY
Enqueue((struct List *)&sdu->sdu_Tx,(struct Node *)ios2);
#else
AddTail((struct List *)&sdu->sdu_Tx,(struct Node *)ios2);
#endif
ReleaseSemaphore(&sdu->sdu_ListLock);
}
}
else
{
/* Sorry, the packet is too long! */
ios2->ios2_Req.io_Error = S2ERR_MTU_EXCEEDED;
ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
TermIO(ios2);
DoEvent(sdu, S2EVENT_TX);
}
}
else
{
/* Sorry, we're offline */
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
TermIO(ios2);
DoEvent(sdu, S2EVENT_TX);
}
}
VOID SendPacket(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
struct IOExtSer *ioser;
struct BufferManagement *bm;
ULONG framelength;
bm =(struct BufferManagement *) ios2->ios2_BufferManagement;
/* Copy the data out of the packet into our temporary buffer. */
if((*bm->bm_CopyFromBuffer)(sdu->sdu_TxBuff,ios2->ios2_Data,ios2->ios2_DataLength))
{
#if CSLIP
struct mbuf m;
unsigned char type;
m.m_off = sdu->sdu_TxBuff;
m.m_len = ios2->ios2_DataLength;
/* Appendix B.1 Living without a framing `type' byte */
type = sl_compress_tcp(&m, &sdu->sdu_slcompress);
m.m_off[0] |= type;
/* Encode the packet in SLIP format */
framelength=EncodeSLIP(m.m_off,sdu->sdu_TxSLIP,m.m_len);
PacketSent(sdu,m.m_len);
#else
/* Encode the packet in SLIP format */
framelength=EncodeSLIP(sdu->sdu_TxBuff,sdu->sdu_TxSLIP,ios2->ios2_DataLength);
PacketSent(sdu,ios2->ios2_DataLength);
#endif
ioser = sdu->sdu_SerTx;
ioser->IOSer.io_Data = sdu->sdu_TxSLIP;
ioser->IOSer.io_Length = framelength;
ioser->IOSer.io_Command = CMD_WRITE;
ioser->IOSer.io_Error = 0;
ioser->IOSer.io_Message.mn_Node.ln_Type = 0;
/* Send the packet to the serial device driver */
SendIO((struct IORequest *)ioser);
}
else
{
/* Something went wrong...*/
ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ios2->ios2_WireError = S2WERR_BUFF_ERROR;
DoEvent(sdu,S2EVENT_BUFF);
}
TermIO(ios2);
}
/*
** This routine encodes a packet in SLIP format.
**
** The format is quite simple.
**
** SLIP Encoding:
**
** SLIP_ESC -> SLIP_ESC SLIP_ESC_ESC
** SLIP_END -> SLIP_ESC SLIP_ESC_END
**
** The packet is preceded and terminated with a SLIP_END as prescribed by
** rfc 1055.
**
*/
ULONG EncodeSLIP(UBYTE *source, UBYTE *dest, ULONG length)
{
UBYTE ch;
UBYTE *current;
current = dest;
*current = SLIP_END;
current++;
while(length--)
{
ch = *source;
source++;
if(ch == SLIP_ESC)
{
*current = SLIP_ESC;
current++;
ch = SLIP_ESC_ESC;
}
else if(ch == SLIP_END)
{
*current = SLIP_ESC;
current ++;
ch = SLIP_ESC_END;
}
*current = ch;
current++;
}
*current = SLIP_END;
current++;
return((ULONG)(current - dest));
}
/*
** This routine handles CMD_READ commands. We
** always queue these unless we're offline.
*/
VOID ReadPacket(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
if(sdu->sdu_State & SLIPUF_ONLINE)
{
/* Queue it... */
ObtainSemaphore(&sdu->sdu_ListLock);
AddTail((struct List *)&sdu->sdu_Rx,(struct Node *)ios2);
#if DEMANDREAD
if (sdu->sdu_SerRx->IOSer.io_Message.mn_Node.ln_Type == NT_FREEMSG)
QueueSerRequest(sdu);
#endif
ReleaseSemaphore(&sdu->sdu_ListLock);
}
else
{
/* Sorry, we're offline */
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
TermIO(ios2);
DoEvent(sdu, S2EVENT_RX);
}
}
/*
** This routine handles CMD_READORPHAN commands. We
** always queue these unless we're offline.
**
** Note: These IO requests will never get satisfied.
** Since SLIP doesn't contain packet type information,
** there is no way to identify what type of packets
** are being received or sent. Thus, we simply ignore
** the packet type and *assume* that the packets are
** IP packets.
*/
VOID ReadOrphan(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
if(sdu->sdu_State & SLIPUF_ONLINE)
{
/* Queue it...*/
ObtainSemaphore(&sdu->sdu_ListLock);
AddTail((struct List *)&sdu->sdu_RxOrph,(struct Node *)ios2);
#if DEMANDREAD
if (sdu->sdu_SerRx->IOSer.io_Message.mn_Node.ln_Type == NT_FREEMSG)
QueueSerRequest(sdu);
#endif
ReleaseSemaphore(&sdu->sdu_ListLock);
}
else
{
/* Sorry, we're offline */
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
DoEvent(sdu, S2EVENT_RX);
TermIO(ios2);
}
}
/*
** This routine initializes our IO requests and buffers
** for serial i/o and SLIP encoding/decoding.
*/
BOOL InitSerial(struct SLIPDevUnit *sdu)
{
ULONG *clr;
BOOL status = FALSE;
for(clr = (ULONG *) &sdu->sdu_SerRx; clr <= (ULONG *) &sdu->sdu_TxSLIP; clr++)
*clr = 0L;
if(sdu->sdu_TxPort = CreateMsgPort())
{
if(sdu->sdu_SerTx = CreateIORequest(sdu->sdu_TxPort,sizeof(struct IOExtSer)))
{
if(sdu->sdu_RxPort = CreateMsgPort())
{
if(sdu->sdu_SerRx = CreateIORequest(sdu->sdu_RxPort,sizeof(struct IOExtSer)))
{
if(sdu->sdu_TxBuff = AllocVec((sdu->sdu_MTU + BUF_SLOP) * 2 + MAX_HDR, MEMF_CLEAR|MEMF_PUBLIC))
{
sdu->sdu_RxBuff = sdu->sdu_TxBuff + sdu->sdu_MTU + BUF_SLOP + MAX_HDR;
sdu->sdu_RxBuffPtr = sdu->sdu_RxBuff;
if(sdu->sdu_TxSLIP = AllocVec((sdu->sdu_MTU * 2 + BUF_SLOP) * 2, MEMF_CLEAR|MEMF_PUBLIC))
{
sdu->sdu_RxSLIP = sdu->sdu_TxSLIP + sdu->sdu_MTU * 2 + BUF_SLOP;
{
status = TRUE;
}
}
}
}
}
}
}
if(!status)
DeinitSerial(sdu);
return(status);
}
/*
** This routine cleans up our serial i/o requests
** and misc. buffers.
*/
VOID DeinitSerial(struct SLIPDevUnit *sdu)
{
if(sdu->sdu_SerTx)
DeleteIORequest(sdu->sdu_SerTx);
if(sdu->sdu_TxPort)
DeleteMsgPort(sdu->sdu_TxPort);
if(sdu->sdu_SerRx)
DeleteIORequest(sdu->sdu_SerRx);
if(sdu->sdu_RxPort)
DeleteMsgPort(sdu->sdu_RxPort);
if(sdu->sdu_TxBuff)
FreeVec(sdu->sdu_TxBuff);
if(sdu->sdu_TxSLIP)
FreeVec(sdu->sdu_TxSLIP);
}
/*
** This routine handles S2_ONEVNET commands.
*/
VOID OnEvent(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
switch(ios2->ios2_WireError)
{
/* Special case. We may already be online, in which
case the IO request should return immediately. Otherwise
we queue it for later. */
case S2EVENT_ONLINE:
if(sdu->sdu_State & SLIPUF_ONLINE)
TermIO(ios2);
else
{
ObtainSemaphore(&sdu->sdu_ListLock);
AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
ReleaseSemaphore(&sdu->sdu_ListLock);
}
break;
/* Same as with S2EVENT_ONLINE, but the opposite
happens. */
case S2EVENT_OFFLINE:
if(sdu->sdu_State & SLIPUF_ONLINE)
{
ObtainSemaphore(&sdu->sdu_ListLock);
AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
ReleaseSemaphore(&sdu->sdu_ListLock);
}
else
TermIO(ios2);
break;
/* Just queue everything else. */
default:
ObtainSemaphore(&sdu->sdu_ListLock);
AddTail((struct List *)&sdu->sdu_Events,(struct Node *)ios2);
ReleaseSemaphore(&sdu->sdu_ListLock);
break;
}
}
/*
** This routine opens the serial device driver and attempts to bring
** the device online.
*/
BOOL OpenSerial(struct SLIPDevUnit *sdu)
{
BOOL status = TRUE;
ULONG odflags;
sdu->sdu_SerRx->IOSer.io_Device = NULL;
odflags = SERF_XDISABLED | SERF_RAD_BOOGIE;
if(sdu->sdu_State & SLIPUF_7WIRE)
odflags |= SERF_7WIRE;
/* Rhialto: odflags must be in io_SerFlags, not in OpenDevice! */
sdu->sdu_SerTx->io_SerFlags = odflags;
if(!OpenDevice(sdu->sdu_SerDevName,sdu->sdu_SerUnitNum,(struct IORequest *)sdu->sdu_SerTx,0))
{
/* Set up our serial parameters */
sdu->sdu_SerRx->IOSer.io_Device = sdu->sdu_SerTx->IOSer.io_Device;
sdu->sdu_SerRx->IOSer.io_Unit = sdu->sdu_SerTx->IOSer.io_Unit;
sdu->sdu_SerTx->IOSer.io_Command = SDCMD_SETPARAMS;
sdu->sdu_SerTx->io_Baud = sdu->sdu_BaudRate;
sdu->sdu_SerTx->io_RBufLen = SLIP_SERIAL_BUFSIZE;
sdu->sdu_SerTx->io_ReadLen = 8;
sdu->sdu_SerTx->io_WriteLen = 8;
sdu->sdu_SerTx->io_StopBits = 1;
sdu->sdu_SerTx->io_SerFlags = odflags;
sdu->sdu_SerTx->io_TermArray.TermArray0 =
sdu->sdu_SerTx->io_TermArray.TermArray1 = 0x01010101 * (UBYTE)SLIP_END;
if(!DoIO((struct IORequest *)sdu->sdu_SerTx))
{
/* Are we checking for serial detect? */
if(sdu->sdu_State & SLIPUF_CD)
{
sdu->sdu_SerTx->IOSer.io_Command = SDCMD_QUERY;
if(!DoIO((struct IORequest *)sdu->sdu_SerTx))
{
if(sdu->sdu_SerTx->io_Status & (1 << 5))
{
/* Sorry, no carrier, shut down the serial driver
and set our state to offline. */
/* ppessi: remove CloseDevice -- use status instead */
status = FALSE;
debug(("No Carrier\n"));
}
}
else
{
status = FALSE;
debug(("QUERY failed %d\n",sdu->sdu_SerTx->io_Error));
}
}
if (status)
{
/* We're now online */
sdu->sdu_State |= SLIPUF_ONLINE;
MarkTimeOnline(sdu);
/* Queue up the initial CMD_READ command for the
serial driver. */
sdu->sdu_SerRx->IOSer.io_Command = CMD_READ;
sdu->sdu_SerRx->IOSer.io_Length = 1;
sdu->sdu_SerRx->IOSer.io_Data = sdu->sdu_RxSLIP;
if(sdu->sdu_State & SLIPUF_EOFMODE)
odflags |= SERF_EOFMODE;
sdu->sdu_SerRx->io_SerFlags = odflags;
sdu->sdu_SerRx->io_TermArray.TermArray0 =
sdu->sdu_SerRx->io_TermArray.TermArray1 = 0x01010101 * (UBYTE)SLIP_END;
SendIO((struct IORequest *)sdu->sdu_SerRx);
}
}
else
{
status = FALSE;
debug(("SETPARAMS failed %d\n",sdu->sdu_SerTx->io_Error));
}
if (!status)
CloseDevice((struct IORequest *)sdu->sdu_SerTx);
}
else
{
struct Library *IntuitionBase;
struct EasyStruct es;
ULONG args[2];
args[0]=(ULONG)sdu->sdu_SerDevName;
args[1]=(ULONG)sdu->sdu_SerUnitNum;
if(IntuitionBase = OpenLibrary("intuition.library",37L))
{
es.es_StructSize=sizeof(struct EasyStruct);
es.es_Flags=0;
es.es_Title=(char *)SLIPName;
es.es_TextFormat="Couldn't open %s unit %ld.";
es.es_GadgetFormat="Okay";
EasyRequestArgs(NULL, &es, 0, (APTR)args);
CloseLibrary(IntuitionBase);
}
status = FALSE;
}
return(status);
}
/*
** This routine gets the current system time and stores
** it in our global statistics structure.
*/
VOID MarkTimeOnline(struct SLIPDevUnit *sdu)
{
register struct Library *TimerBase;
struct timerequest *treq;
if(treq = (struct timerequest *)AllocMem(sizeof(struct timerequest),MEMF_PUBLIC|MEMF_CLEAR))
{
if(!OpenDevice("timer.device",UNIT_MICROHZ,(struct IORequest *)treq,0L))
{
TimerBase = (struct Library *)treq->tr_node.io_Device;
GetSysTime(&sdu->sdu_Stats.LastStart);
CloseDevice((struct IORequest *)treq);
}
FreeMem(treq,sizeof(struct timerequest));
}
}
/*
** This routine aborts any pending activity with the serial
** device driver and then brings the slip driver offline.
*/
VOID CloseSerial(struct SLIPDevUnit *sdu)
{
if (!CheckIO((struct IORequest *)sdu->sdu_SerRx) &&
sdu->sdu_SerRx->IOSer.io_Message.mn_Node.ln_Type != NT_FREEMSG) {
AbortIO((struct IORequest *)sdu->sdu_SerRx);
WaitIO((struct IORequest *)sdu->sdu_SerRx);
}
while(GetMsg(sdu->sdu_RxPort));
if (!CheckIO((struct IORequest *)sdu->sdu_SerTx)) {
AbortIO((struct IORequest *)sdu->sdu_SerTx);
WaitIO((struct IORequest *)sdu->sdu_SerTx);
}
while(GetMsg(sdu->sdu_TxPort));
CloseDevice((struct IORequest *)sdu->sdu_SerRx);
sdu->sdu_State &= ~SLIPUF_ONLINE;
}
/*
** This routime handles CMD_ONLINE commands.
*/
VOID Online(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
if(!(sdu->sdu_State & SLIPUF_ONLINE))
{
/* We're offline. Try to go online. */
if(OpenSerial(sdu))
{
if(sdu->sdu_State & SLIPUF_ONLINE)
{
/* In case someone wants to know...*/
DoEvent(sdu, S2EVENT_ONLINE);
}
else
{
/* Sorry, the attempt to go online failed. */
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
}
}
else
{
/* A general problem occured. */
ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ios2->ios2_WireError = S2WERR_GENERIC_ERROR;
}
}
TermIO(ios2);
}
/*
** This routine handles CMD_OFFLINE commands.
*/
VOID Offline(struct SLIPDevUnit *sdu, struct IOSana2Req *ios2)
{
TermIO(ios2);
if(sdu->sdu_State & SLIPUF_ONLINE)
{
/* We're online, so shut everything down. */
CloseSerial(sdu);
DoOffline(sdu);
DoEvent(sdu,S2EVENT_OFFLINE);
}
}
/*
** This routine is called whenever an "important"
** SANA-II event occurs.
*/
VOID DoEvent(struct SLIPDevUnit *sdu, ULONG event)
{
struct IOSana2Req *ios2;
struct IOSana2Req *ios2_next;
ObtainSemaphore(&sdu->sdu_ListLock);
ios2 = (struct IOSana2Req *)sdu->sdu_Events.mlh_Head;
while(ios2->ios2_Req.io_Message.mn_Node.ln_Succ)
{
ios2_next = (struct IOSana2Req *)ios2->ios2_Req.io_Message.mn_Node.ln_Succ;
/* Is this the event they are looking for? */
if(ios2->ios2_WireError == event)
{
Remove((struct Node *)ios2);
TermIO(ios2);
}
ios2 = ios2_next;
}
ReleaseSemaphore(&sdu->sdu_ListLock);
}
/*
** This routine is called whenever the device needs to
** be taken offline. We return any pending CMD_READ's
** or CMD_WRITE's to their senders.
*/
VOID DoOffline(struct SLIPDevUnit *sdu)
{
struct IOSana2Req *ios2;
ObtainSemaphore(&sdu->sdu_ListLock);
while(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Rx))
{
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
TermIO(ios2);
}
while(ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Tx))
{
ios2->ios2_Req.io_Error = S2ERR_OUTOFSERVICE;
ios2->ios2_WireError = S2WERR_UNIT_OFFLINE;
TermIO(ios2);
}
ReleaseSemaphore(&sdu->sdu_ListLock);
}
/*
** This routine is called whenever a CMD_WRITE request
** has returned from the serial driver.
*/
VOID ServiceTxPort(struct SLIPDevUnit *sdu)
{
struct IOSana2Req *ios2;
/* See if we have any pending CMD_WRITE requests. */
if(sdu->sdu_State & SLIPUF_ONLINE)
{
ObtainSemaphore(&sdu->sdu_ListLock);
ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Tx);
ReleaseSemaphore(&sdu->sdu_ListLock);
if(ios2)
{
SendPacket(sdu, ios2);
}
}
}
/*
** This routine is called whenever a CMD_READ request
** returns from the serial driver. It decodes the
** packet data and tries to build complete packets.
*/
VOID DoSerial(struct SLIPDevUnit *sdu, struct IOExtSer *ioSer)
{
UBYTE *rx_ptr,*packet_ptr;
UBYTE rx_byte, packet_byte;
ULONG length;
packet_ptr = sdu->sdu_RxBuffPtr;
rx_ptr = sdu->sdu_RxSLIP;
length = ioSer->IOSer.io_Actual; /* Rhialto: Was io_Length */
while(length--)
{
rx_byte = packet_byte = *rx_ptr;
rx_ptr++;
/* Handle SLIP packet decoding...*/
if(sdu->sdu_Escape)
{
if(rx_byte == SLIP_ESC_ESC)
packet_byte = SLIP_ESC;
else if(rx_byte = SLIP_ESC_END)
packet_byte = SLIP_END;
else
ReceivedGarbage(sdu); /* This packet may be hosed */
sdu->sdu_Escape = FALSE;
}
else if(rx_byte == SLIP_ESC)
{
sdu->sdu_Escape = TRUE;
continue;
}
else if(rx_byte == SLIP_END)
{
GotPacket(sdu,(ULONG)(packet_ptr - sdu->sdu_RxBuff));
packet_ptr = sdu->sdu_RxBuff;
continue;
}
*packet_ptr = packet_byte;
packet_ptr++;
if(((ULONG)(packet_ptr - sdu->sdu_RxBuff)) > sdu->sdu_MTU)
{
packet_ptr = sdu->sdu_RxBuff;
PacketOverrun(sdu);
}
}
sdu->sdu_RxBuffPtr = packet_ptr;
/* Queue up another CMD_READ request...*/
#if DEMANDREAD
/* Rhialto: but only if we are sure that we won't drop that packet */
ObtainSemaphore(&sdu->sdu_ListLock);
/* Semaphore protection of sdu_Rx, sdu_RxOrph, and sdu_Tx is not
* really necessary, since they are only accessed from the
* Unit task, because there are no IMMEDIATE device commands.
*/
/* Semaphore protection *is* needed due AbortIO //ppessi */
if (!IsListEmpty((struct List *)&sdu->sdu_Rx) ||
!IsListEmpty((struct List *)&sdu->sdu_RxOrph))
QueueSerRequest(sdu);
else
sdu->sdu_SerRx->IOSer.io_Message.mn_Node.ln_Type = NT_FREEMSG;
ReleaseSemaphore(&sdu->sdu_ListLock);
#else
QueueSerRequest(sdu);
#endif
}
/*
** This routine is called whenever we think we've got
** a complete packet to satisfy a CMD_READ request.
*/
VOID GotPacket(struct SLIPDevUnit *sdu, ULONG length)
{
struct IOSana2Req *ios2;
struct BufferManagement *bm;
/* We ignore zero-length packets. These occur
in between legal SLIP packets due to the
way SLIP packets are framed. */
if(length)
{
short orphan;
PacketReceived(sdu,length);
ObtainSemaphore(&sdu->sdu_ListLock);
ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_Rx);
if (orphan = ios2 == NULL)
ios2 = (struct IOSana2Req *)RemHead((struct List *)&sdu->sdu_RxOrph);
ReleaseSemaphore(&sdu->sdu_ListLock);
if(ios2)
{
#if CSLIP
/* Appendix B.1 Living without a framing `type' byte */
struct mbuf m;
unsigned char type;
m.m_off = sdu->sdu_RxBuff;
m.m_len = length;
type = m.m_off[0];
if (type & 0x80)
type = TYPE_COMPRESSED_TCP;
else if (type >= 0x70) {
type = TYPE_UNCOMPRESSED_TCP;
m.m_off[0] &= ~0x30;
} else
type = TYPE_IP;
if (NULL == sl_uncompress_tcp(&m, type, &sdu->sdu_slcompress))
{
/* put the ios2 back to queue or they will be lost //ppessi */
ObtainSemaphore(&sdu->sdu_ListLock);
if (orphan)
AddHead((struct List *)&sdu->sdu_RxOrph, (struct Node*)ios2);
else
AddHead((struct List *)&sdu->sdu_Rx, (struct Node*)ios2);
ReleaseSemaphore(&sdu->sdu_ListLock);
return;
}
bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
/* Copy the data into the protocol stack's buffer using its
supplied callback routine. */
if((*bm->bm_CopyToBuffer)(ios2->ios2_Data,m.m_off,m.m_len))
{
ios2->ios2_DataLength = m.m_len;
}
#else
bm = (struct BufferManagement *)ios2->ios2_BufferManagement;
/* Copy the data into the protocol stack's buffer using its
supplied callback routine. */
if((*bm->bm_CopyToBuffer)(ios2->ios2_Data,sdu->sdu_RxBuff,length))
{
ios2->ios2_DataLength = length;
}
#endif
else
{
ios2->ios2_DataLength = 0;
ios2->ios2_Req.io_Error = S2ERR_NO_RESOURCES;
ios2->ios2_WireError = S2WERR_BUFF_ERROR;
DoEvent(sdu,S2EVENT_BUFF);
}
TermIO(ios2);
}
else
PacketDropped(sdu);
}
sdu->sdu_Escape = 0;
}
/*
** This routine is called whenever we need to
** get more data from the serial port. We first
** to a SDCMD_QUERY to see how much data is available,
** if any.
** Rhialto: without EOF mode, this makes the thing a real CPU hog,
** as long as input is coming in and read requests are pending.
** And since it runs at pri 5, that is a real disaster.
*/
VOID QueueSerRequest(struct SLIPDevUnit *sdu)
{
if ((sdu->sdu_State & SLIPUF_EOFMODE) == 0 || (sdu->sdu_State & SLIPUF_CD))
{
sdu->sdu_SerRx->IOSer.io_Command = SDCMD_QUERY;
DoIO((struct IORequest *)sdu->sdu_SerRx);
if (sdu->sdu_State & SLIPUF_CD)
{
if (sdu->sdu_SerRx->io_Status & (1<<5))
{
/* Oops! We've lost carrier. Go offline. */
CloseSerial(sdu);
DoOffline(sdu);
DoEvent(sdu,S2EVENT_OFFLINE);
return;
}
}
}
sdu->sdu_SerRx->IOSer.io_Command = CMD_READ;
sdu->sdu_SerRx->IOSer.io_Data = sdu->sdu_RxSLIP;
if (sdu->sdu_State & SLIPUF_EOFMODE)
{
sdu->sdu_SerRx->IOSer.io_Length = sdu->sdu_MTU * 2 + 1;
}
else
{
/* Rhialto: This could lead to requesting more than the buffer
* size! The serial.device has a 16K buffer. (See SDCMD_SETPARAMS)
*/
sdu->sdu_SerRx->IOSer.io_Length = sdu->sdu_SerRx->IOSer.io_Actual;
if (sdu->sdu_SerRx->IOSer.io_Length > (sdu->sdu_MTU * 2 + BUF_SLOP))
sdu->sdu_SerRx->IOSer.io_Length = (sdu->sdu_MTU * 2 + BUF_SLOP);
else
/* If the number of bytes available is zero, queue a request
for one byte. */
if(!sdu->sdu_SerRx->IOSer.io_Length)
sdu->sdu_SerRx->IOSer.io_Length = 1;
}
SendIO((struct IORequest *)sdu->sdu_SerRx);
}
/*
** This is the C entry point for the Unit process.
*/
VOID ASM DevProcCEntry(VOID)
{
struct Process *proc;
struct SLIPDevUnit *sdu;
struct IOExtSer *ioser;
struct StartupMessage *sm;
struct BufferManagement *bm;
struct IOSana2Req *ios2;
ULONG waitmask, signals;
UBYTE signalbit;
/* Find our Process pointer and wait for our startup
message to arrive. */
proc = (struct Process *)FindTask(0L);
WaitPort(&proc->pr_MsgPort);
/* Pull the startup message off of our process messageport. */
sm = (struct StartupMessage *)GetMsg(&proc->pr_MsgPort);
/* Grab our Unit pointer. */
sdu = (struct SLIPDevUnit *)sm->Unit;
/* Attempt to allocate a signal bit for our Unit MsgPort. */
signalbit = AllocSignal(-1L);
if(signalbit != -1)
{
/* Set up our Unit's MsgPort. */
sdu->sdu_Unit.unit_MsgPort.mp_SigBit = signalbit;
sdu->sdu_Unit.unit_MsgPort.mp_SigTask = (struct Task *)proc;
sdu->sdu_Unit.unit_MsgPort.mp_Flags = PA_SIGNAL;
/* Initialize our list semaphore */
InitSemaphore(&sdu->sdu_ListLock);
/* Initialize our linked lists. */
NewList((struct List *)&sdu->sdu_Rx);
NewList((struct List *)&sdu->sdu_RxOrph);
NewList((struct List *)&sdu->sdu_Tx);
NewList((struct List *)&sdu->sdu_Events);
NewList((struct List *)&sdu->sdu_BuffMgmt);
NewList((struct List *)&sdu->sdu_Track);
#if CSLIP
/* Initialise the compression stuff */
sl_compress_init(&sdu->sdu_slcompress, 16, 16);
#endif
/* Initialize the serial stuff. If all goes okay,
set sdu->sdu_Proc to pointer to our unit process.
This will let the Unit init code know that were
are okay. */
if(InitSerial(sdu))
sdu->sdu_Proc = proc;
}
/* Reply to our startup message */
ReplyMsg((struct Message *)sm);
/* Check sdu->sdu_Proc to see if everything went okay up
above. */
if(sdu->sdu_Proc)
{
waitmask = (1L<<signalbit) | (1L<<sdu->sdu_RxPort->mp_SigBit) |
(1L<<sdu->sdu_TxPort->mp_SigBit) | SIGBREAKF_CTRL_F;
/* Loop...*/
while (TRUE)
{
int More;
signals = Wait(waitmask);
/* Have we been signaled to shut down? */
if (signals & SIGBREAKF_CTRL_F)
break;
do {
More = FALSE;
if (ios2 = (struct IOSana2Req *)GetMsg((struct MsgPort *)sdu))
{
More = TRUE;
PerformIO(ios2);
}
if (ioser = (struct IOExtSer *)GetMsg(sdu->sdu_RxPort))
{
More = TRUE;
if(sdu->sdu_State & SLIPUF_ONLINE)
{
DoSerial(sdu, ioser);
}
}
if (ioser = (struct IOExtSer *)GetMsg(sdu->sdu_TxPort))
{
More = TRUE;
ServiceTxPort(sdu);
}
} while (More);
}
/* If we're online, we need to shut everything down. */
if(sdu->sdu_State & SLIPUF_ONLINE)
{
CloseSerial(sdu);
FreeSignal(signalbit);
while(bm = (struct BufferManagement *)RemHead((struct List *)&sdu->sdu_BuffMgmt))
FreeMem(bm, sizeof(struct BufferManagement));
}
DeinitSerial(sdu);
#if CSLIP
sl_compress_deinit(&sdu->sdu_slcompress);
#endif
/* Signal the other side we're exiting. Make sure that
we exit before they wake up by using the same trick
when replying to Workbench startup messages. */
Forbid();
Signal((struct Task *)sdu->sdu_Proc, SIGBREAKF_CTRL_F);
}
/* Something went wrong in the init code. Drop out. */
else
{
if(signalbit)
FreeSignal(signalbit);
}
}
/* List init routine. */
VOID NewList(struct List *list)
{
list->lh_Head = (struct Node *)&list->lh_Tail;
list->lh_Tail = NULL;
list->lh_TailPred = (struct Node *)list;
}